package com.xj.nrpc.client.proxy;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;

import com.xj.nrpc.client.TCPClient;
import com.xj.nrpc.core.annotation.RemoteInvoking;
import com.xj.nrpc.core.util.RequestEntity;
import com.xj.nrpc.core.util.ResponseEntity;

@Component
public class InvokeProxy implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		Field[] fileds = bean.getClass().getDeclaredFields();
		for(Field f : fileds){
			if(f.isAnnotationPresent(RemoteInvoking.class)){
				f.setAccessible(true);
				Enhancer hancer = new Enhancer();
				hancer.setInterfaces(new Class[]{f.getType()});
				
				final Map<Method, Class<?>> methodMap = new HashMap<Method, Class<?>>();
				setMethodMap(methodMap, f);
				hancer.setCallback(new MethodInterceptor() {
					@Override
					public Object intercept(Object instance, Method method, Object[] args, MethodProxy proxy) throws Throwable {
						RequestEntity request = new RequestEntity();
						request.setCommond(methodMap.get(method).getName()+"."+method.getName());
						request.setData(args[0]);
						request.setId(Math.random()+"");
						ResponseEntity resp = TCPClient.send(request );
						
						return resp;
					}
				});
				try {
					f.set(bean, hancer.create());
				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
		return bean;
	}
	
	private void setMethodMap(Map<Method, Class<?>> methodMap,Field f){
		Method[] ms = f.getType().getDeclaredMethods();
		for(Method m : ms){
			methodMap.put(m, f.getType());
		}
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}
